package javacommon.base;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.dao.support.DaoSupport;
import org.springframework.orm.ibatis.SqlMapClientCallback;
import org.springframework.orm.ibatis.SqlMapClientTemplate;
import org.springframework.util.Assert;

import com.ibatis.sqlmap.client.SqlMapExecutor;

import cn.org.rapid_framework.beanutils.BeanUtils;
import cn.org.rapid_framework.page.Page;
import cn.org.rapid_framework.page.PageRequest;

/**
 * @author badqiu
 * @version 1.0
 */
public abstract class BaseIbatis3Dao<E, PK extends Serializable> extends DaoSupport implements EntityDao<E, PK>
{
   protected final Log log = LogFactory.getLog(getClass());

   private SqlSessionFactory sqlSessionFactory;
   private SqlSessionTemplate sqlSessionTemplate;
   private SqlMapClientTemplate sqlMapClientTemplate;

   private int seq = 10; // 搴忓垪,鍙栧�鑼冨洿浠�0鍒�9锛� 鐢ㄤ簬浜х敓浠诲姟ID

   public SqlMapClientTemplate getSqlMapClientTemplate()
   {
      return sqlMapClientTemplate;
   }

   public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate)
   {
      this.sqlMapClientTemplate = sqlMapClientTemplate;
   }

   protected void checkDaoConfig() throws IllegalArgumentException
   {
      Assert.notNull("sqlSessionFactory must be not null");
   }

   public SqlSessionFactory getSqlSessionFactory()
   {
      return sqlSessionFactory;
   }

   public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory)
   {
      this.sqlSessionFactory = sqlSessionFactory;
      this.sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
   }

   public abstract Class getEntityClass();

   public SqlSessionTemplate getSqlSessionTemplate()
   {
      return sqlSessionTemplate;
   }

   public Object getById(PK primaryKey)
   {
      Object object = getSqlSessionTemplate().selectOne(getFindByPrimaryKeyQuery(), primaryKey);
      return object;
   }

   // 鍒犻櫎瀵硅薄杩斿洖INT锛堝垬鏂囪緣 2010-06-01锛�
   public int delete(final String statement, final Object parameter)
   {
      return getSqlSessionTemplate().delete(statement, parameter);
   }

   public void deleteById(PK id)
   {
      getSqlSessionTemplate().delete(getDeleteQuery(), id);
   }

   // 鏂板瀵硅薄杩斿洖INT锛堝垬鏂囪緣 2010-06-01锛�
   public int save(final String statement, final Object parameter)
   {
      return getSqlSessionTemplate().insert(statement, parameter);
   }

   // 鏂板瀵硅薄杩斿洖INT锛坆zq 2010-06-11锛�
   public int update(final String statement, final Object parameter)
   {
      return getSqlSessionTemplate().update(statement, parameter);
   }

   public void save(E entity)
   {
      prepareObjectForSaveOrUpdate(entity);
      Object primaryKey = getSqlSessionTemplate().insert(getInsertQuery(), entity);

   }

   // 鎵归噺鎻掑叆
   public void batchInsert(final List list)
   {//
      try
      {
         if(list != null)
         {

            this.getSqlMapClientTemplate().execute(new SqlMapClientCallback()
            {
               public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException
               {
                  try
                  {
                     executor.startBatch();
                     for(int i = 0, n = list.size(); i < n; i++)
                     {
                        // executor.insert(getInsertQuery(), list.get(i));
                        sqlSessionFactory.openSession().insert(getInsertQuery(), list.get(i));
                        if(i % 1000 == 0)
                        {
                           executor.executeBatch();
                        }

                     }
                     executor.executeBatch();
                  }
                  catch (Exception e)
                  {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                  }

                  return null;
               }
            });
         }
      }
      catch (Exception e)
      {
         if(log.isDebugEnabled())
         {
            e.printStackTrace();
            log.fatal("batchInsert error: id [" + getInsertQuery() + "], parameterObject [" + list + "].  Cause: " + e.getMessage());
         }
      }

   }

   public List getList(final String statement, final Object parameter)
   {
      List list = getSqlSessionTemplate().selectList(statement, parameter);
      return list;
   }

   public void update(E entity)
   {
      prepareObjectForSaveOrUpdate(entity);
      Object primaryKey = getSqlSessionTemplate().update(getUpdateQuery(), entity);
   }

   /**
    * 鐢ㄤ簬瀛愮被瑕嗙洊,鍦╥nsert,update涔嬪墠璋冪敤
    * 
    * @param o
    */
   protected void prepareObjectForSaveOrUpdate(E o)
   {
   }

   public String getFindByPrimaryKeyQuery()
   {
      return getEntityClass().getSimpleName() + ".getById";
   }

   public String getInsertQuery()
   {
      return getEntityClass().getSimpleName() + ".insert";
   }

   public String getUpdateQuery()
   {
      return getEntityClass().getSimpleName() + ".update";
   }

   public String getDeleteQuery()
   {
      return getEntityClass().getSimpleName() + ".delete";
   }

   public String getCountQuery()
   {
      return getEntityClass().getSimpleName() + ".count";
   }

   /** 鏌ヨ鎵�湁 */
   public String getFindAllQuery()
   {
      return getEntityClass().getSimpleName() + ".findAll";
   }

   /** 鏌ヨ鍒楄〃杩斿洖List */
   public String getFindListQuery()
   {
      return getEntityClass().getSimpleName() + ".findList";
   }

   public String getCallQuery()
   {
      return getEntityClass().getSimpleName() + ".callStatic";
   }

   protected Page pageQuery(String statementName, PageRequest pageRequest)
   {

      Number totalCount = (Number) this.getSqlSessionTemplate().selectOne(getCountQuery(), pageRequest.getFilters());
      if(totalCount == null || totalCount.intValue() <= 0)
      {
         return new Page(pageRequest, 0);
      }

      Page page = new Page(pageRequest, totalCount.intValue());

      // 鍏跺畠鍒嗛〉鍙傛暟,鐢ㄤ簬涓嶅枩娆㈡垨鏄洜涓哄吋瀹规�鑰屼笉浣跨敤鏂硅█(Dialect)鐨勫垎椤电敤鎴蜂娇鐢�
      // 涓巊etSqlMapClientTemplate().queryForList(statementName,
      // parameterObject)閰嶅悎浣跨敤
      Map filters = new HashMap();
      filters.put("offset", page.getFirstResult());
      filters.put("pageSize", page.getPageSize());
      filters.put("lastRows", page.getFirstResult() + page.getPageSize());
      filters.put("sortColumns", pageRequest.getSortColumns());

      // 娣峰悎涓や釜filters涓轰竴涓猣ilters,MapAndObject.get()鏂规硶灏嗗湪涓や釜瀵硅薄鍙栧�,Map濡傛灉鍙栧�涓簄ull,鍒欏啀鍦˙ean涓彇鍊�
      if(pageRequest.getFilters() instanceof Map)
      {
         filters.putAll((Map) pageRequest.getFilters());
      }
      else
      {
         Map parameterObject = BeanUtils.describe(pageRequest.getFilters());
         filters.putAll(parameterObject);
      }

      List list = getSqlSessionTemplate().selectList(statementName, filters, page.getFirstResult(), page.getPageSize());
      page.setResult(list);
      return page;
   }

   /**
    * 鑷繁瀹氫箟瀹炵幇鍒嗛〉鏌ヨ
    * 
    * @param statementName
    *           鏌ヨ鏁版嵁SQL
    * @param pageRequest
    * @param countSql
    *           鏌ヨ鍒嗛〉鎬昏褰曟暟 sql
    * @author bzq add
    * @return
    */
   protected Page pageQuery(String statementName, String countSql, PageRequest pageRequest)
   {
      // System.out.println("@@@ "+countSql);
      Number totalCount = (Number) getSqlSessionTemplate().selectOne(countSql, pageRequest.getFilters());
      if(totalCount == null || totalCount.intValue() <= 0)
      {
         return new Page(pageRequest, 0);
      }
      // System.out.println("@@@ "+totalCount);
      Page page = new Page(pageRequest, totalCount.intValue());

      // 鍏跺畠鍒嗛〉鍙傛暟,鐢ㄤ簬涓嶅枩娆㈡垨鏄洜涓哄吋瀹规�鑰屼笉浣跨敤鏂硅█(Dialect)鐨勫垎椤电敤鎴蜂娇鐢�
      // 涓巊etSqlMapClientTemplate().queryForList(statementName,
      // parameterObject)閰嶅悎浣跨敤
      Map filters = new HashMap();
      filters.put("offset", page.getFirstResult());
      filters.put("pageSize", page.getPageSize());
      filters.put("lastRows", page.getFirstResult() + page.getPageSize());
      filters.put("sortColumns", pageRequest.getSortColumns());

      // 娣峰悎涓や釜filters涓轰竴涓猣ilters,MapAndObject.get()鏂规硶灏嗗湪涓や釜瀵硅薄鍙栧�,Map濡傛灉鍙栧�涓簄ull,鍒欏啀鍦˙ean涓彇鍊�
      if(pageRequest.getFilters() instanceof Map)
      {
         filters.putAll((Map) pageRequest.getFilters());
      }
      else
      {
         Map parameterObject = cn.org.rapid_framework.beanutils.BeanUtils.describe(pageRequest.getFilters());
         filters.putAll(parameterObject);
      }

      List list = getSqlSessionTemplate().selectList(statementName, filters, page.getFirstResult(), page.getPageSize());
      page.setResult(list);
      return page;
   }

   /**
    * <p>
    * 鏌ヨ鏁版嵁<br>
    * 
    * @param Map
    *           map
    * @return List
    * @author bzq add
    */
   public List findList(Map map)
   {
      List list = getSqlSessionTemplate().selectList(getFindListQuery(), map);
      return list;
   }

   public void callOrderStatic(Map map)
   {
      // sqlSessionFactory.openSession().
      getSqlSessionTemplate().update(getCallQuery(), map);

   }

   /**
    * <p>
    * 鏌ヨ鎵�湁鏁版嵁<br>
    * 
    * @return List
    * @author bzq update
    */
   public List findAll()
   {
      List list = getSqlSessionTemplate().selectList(getFindAllQuery(), null);
      return list;
   }

   /**
    * public List findAll() { List list =
    * getSqlSessionTemplate().selectList(getFindAllQuery(), null); return list;
    * }
    */
   public boolean isUnique(E entity, String uniquePropertyNames)
   {
      throw new UnsupportedOperationException();
   }

   public void flush()
   {
      // ignore
   }

   public static class SqlSessionTemplate
   {
      SqlSessionFactory sqlSessionFactory;

      public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory)
      {
         this.sqlSessionFactory = sqlSessionFactory;
      }

      public Object execute(SqlSessionCallback action)
      {
         SqlSession session = null;
         try
         {
            session = sqlSessionFactory.openSession();
            Object result = action.doInSession(session);
            return result;
         }
         finally
         {
            if(session != null) session.close();
         }
      }

      public Object selectOne(final String statement, final Object parameter)
      {
         return execute(new SqlSessionCallback()
         {
            public Object doInSession(SqlSession session)
            {
               return session.selectOne(statement, parameter);
            }
         });
      }

      public List selectList(final String statement, final Object parameter, final int offset, final int limit)
      {
         return (List) execute(new SqlSessionCallback()
         {
            public Object doInSession(SqlSession session)
            {
               return session.selectList(statement, parameter, new RowBounds(offset, limit));
            }
         });
      }

      // 姝ゆ柟娉曚负娼樺僵铏�010-5-26鍐�
      public List selectList(final String statement, final Object parameter)
      {
         return (List) execute(new SqlSessionCallback()
         {
            public Object doInSession(SqlSession session)
            {
               return session.selectList(statement, parameter);
            }
         });
      }

      public int delete(final String statement, final Object parameter)
      {
         return (Integer) execute(new SqlSessionCallback()
         {
            public Object doInSession(SqlSession session)
            {
               return session.delete(statement, parameter);
            }
         });
      }

      public int update(final String statement, final Object parameter)
      {
         return (Integer) execute(new SqlSessionCallback()
         {
            public Object doInSession(SqlSession session)
            {
               return session.update(statement, parameter);
            }
         });
      }

      public int insert(final String statement, final Object parameter)
      {
         return (Integer) execute(new SqlSessionCallback()
         {
            public Object doInSession(SqlSession session)
            {
               return session.insert(statement, parameter);
            }
         });
      }
   }

   /**
    * author : 闄堜功鍗� create time : Jun 29, 2010; modify time : Jun 29, 2010;
    * return : String; 鏌ヨ搴忓垪鐨勫�
    */

   public String findId(String statement)
   {
      String id = null;
      try
      {
         id = (String) this.getSqlSessionTemplate().selectOne(statement, null);
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
      return id;
   }

   public String createTaskID()
   {
      java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyMMddHHmm"); // 鐢ㄦ潵褰㈡垚瑙勮寖鐨勬棩鏈熸牸寮�
      String curr_time = format.format(new java.util.Date(System.currentTimeMillis()));
      seq++;
      if(seq >= 100)
      {
         seq = 10;
      }

      return curr_time + String.valueOf(seq);
   }

   public static interface SqlSessionCallback
   {

      public Object doInSession(SqlSession session);

   }

}
